#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""文件管理模块"""

import os
import io
import json
import logging
import chardet
from datetime import datetime


class FileManager:
    """文件管理类，负责文件的创建、打开、保存等操作"""
    
    def __init__(self):
        """初始化文件管理器"""
        # 当前打开的文件
        self.current_file_path = None
        
        # 文件内容缓存
        self.file_content_cache = {}
        
        # 文件修改状态
        self.file_modified = False
        
        # 最近打开的文件列表
        self.recent_files = []
        self.max_recent_files = 10
        
        # 支持的文件类型
        self.supported_file_types = {
            "Python": [".py"],
            "JSON": [".json"],
            "XML": [".xml"],
            "HTML": [".html", ".htm"],
            "CSS": [".css"],
            "JavaScript": [".js", ".jsx"],
            "TypeScript": [".ts", ".tsx"],
            "Markdown": [".md"],
            "Text": [".txt", ".log", ".ini", ".cfg", ""]
        }
        
        # 日志配置
        logging.basicConfig(
            level=logging.INFO,
            format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
        )
        self.logger = logging.getLogger("FileManager")
    
    def create_new_file(self, file_path=None, initial_content=""):
        """创建新文件
        
        Args:
            file_path: 文件路径，如果为None则创建临时文件
            initial_content: 初始内容
            
        Returns:
            tuple: (是否成功, 消息, 文件路径)
        """
        try:
            # 如果没有指定文件路径，创建临时文件
            if not file_path:
                import tempfile
                fd, file_path = tempfile.mkstemp(suffix=".py")
                os.close(fd)
            
            # 检查文件是否已存在
            if os.path.exists(file_path):
                self.logger.warning(f"文件 '{file_path}' 已存在")
                return False, "文件已存在", file_path
            
            # 创建目录（如果不存在）
            dir_path = os.path.dirname(file_path)
            if dir_path and not os.path.exists(dir_path):
                os.makedirs(dir_path)
            
            # 写入初始内容
            with open(file_path, "w", encoding="utf-8") as f:
                f.write(initial_content)
            
            # 更新当前文件
            self.current_file_path = file_path
            self.file_content_cache[file_path] = initial_content
            self.file_modified = False
            
            # 添加到最近打开的文件列表
            self._add_to_recent_files(file_path)
            
            self.logger.info(f"文件 '{file_path}' 创建成功")
            return True, "文件创建成功", file_path
        except Exception as e:
            self.logger.error(f"创建文件失败: {str(e)}")
            return False, f"创建文件失败: {str(e)}", None
    
    def open_file(self, file_path):
        """打开文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            tuple: (是否成功, 消息, 文件内容, 编码)
        """
        try:
            # 检查文件是否存在
            if not os.path.exists(file_path):
                self.logger.error(f"文件 '{file_path}' 不存在")
                return False, "文件不存在", None, None
            
            # 检查文件是否为目录
            if os.path.isdir(file_path):
                self.logger.error(f"'{file_path}' 是一个目录，不是文件")
                return False, "选择的是目录，不是文件", None, None
            
            # 检测文件编码
            with open(file_path, 'rb') as f:
                raw_data = f.read()
                result = chardet.detect(raw_data)
                encoding = result['encoding'] or 'utf-8'
                confidence = result['confidence']
                
                # 如果置信度较低，尝试使用utf-8
                if confidence < 0.7:
                    try:
                        # 尝试使用utf-8解码
                        content = raw_data.decode('utf-8')
                        encoding = 'utf-8'
                    except UnicodeDecodeError:
                        # 如果utf-8失败，使用检测到的编码
                        content = raw_data.decode(encoding, errors='replace')
                else:
                    # 使用检测到的编码
                    content = raw_data.decode(encoding, errors='replace')
            
            # 更新当前文件
            self.current_file_path = file_path
            self.file_content_cache[file_path] = content
            self.file_modified = False
            
            # 添加到最近打开的文件列表
            self._add_to_recent_files(file_path)
            
            self.logger.info(f"文件 '{file_path}' 打开成功")
            return True, "文件打开成功", content, encoding
        except Exception as e:
            self.logger.error(f"打开文件失败: {str(e)}")
            return False, f"打开文件失败: {str(e)}", None, None
    
    def save_file(self, content=None, file_path=None):
        """保存文件
        
        Args:
            content: 文件内容，如果为None则使用缓存的内容
            file_path: 文件路径，如果为None则使用当前文件路径
            
        Returns:
            tuple: (是否成功, 消息, 文件路径)
        """
        try:
            # 确定文件路径
            if not file_path:
                file_path = self.current_file_path
            
            if not file_path:
                self.logger.error("没有指定文件路径")
                return False, "没有指定文件路径", None
            
            # 确定文件内容
            if content is None:
                if file_path in self.file_content_cache:
                    content = self.file_content_cache[file_path]
                else:
                    self.logger.error(f"文件 '{file_path}' 的内容缓存不存在")
                    return False, "文件内容缓存不存在", file_path
            
            # 创建目录（如果不存在）
            dir_path = os.path.dirname(file_path)
            if dir_path and not os.path.exists(dir_path):
                os.makedirs(dir_path)
            
            # 写入文件
            with open(file_path, "w", encoding="utf-8") as f:
                f.write(content)
            
            # 更新文件缓存和状态
            self.file_content_cache[file_path] = content
            self.file_modified = False
            
            # 如果是新文件，设置为当前文件并添加到最近打开的文件列表
            if file_path != self.current_file_path:
                self.current_file_path = file_path
                self._add_to_recent_files(file_path)
            
            self.logger.info(f"文件 '{file_path}' 保存成功")
            return True, "文件保存成功", file_path
        except Exception as e:
            self.logger.error(f"保存文件失败: {str(e)}")
            return False, f"保存文件失败: {str(e)}", file_path
    
    def save_file_as(self, file_path, content=None):
        """另存为文件
        
        Args:
            file_path: 新文件路径
            content: 文件内容，如果为None则使用当前文件的内容
            
        Returns:
            tuple: (是否成功, 消息, 文件路径)
        """
        # 调用保存文件方法
        return self.save_file(content, file_path)
    
    def close_file(self, file_path=None):
        """关闭文件
        
        Args:
            file_path: 文件路径，如果为None则关闭当前文件
        """
        try:
            # 确定文件路径
            if not file_path:
                file_path = self.current_file_path
            
            if not file_path:
                return True, "没有打开的文件"
            
            # 检查文件是否有未保存的修改
            if self.file_modified:
                self.logger.warning(f"文件 '{file_path}' 有未保存的修改")
                return False, "文件有未保存的修改"
            
            # 从缓存中移除文件
            if file_path in self.file_content_cache:
                del self.file_content_cache[file_path]
            
            # 如果关闭的是当前文件，清除当前文件
            if file_path == self.current_file_path:
                self.current_file_path = None
            
            self.file_modified = False
            
            self.logger.info(f"文件 '{file_path}' 关闭成功")
            return True, "文件关闭成功"
        except Exception as e:
            self.logger.error(f"关闭文件失败: {str(e)}")
            return False, f"关闭文件失败: {str(e)}"
    
    def get_file_content(self, file_path=None):
        """获取文件内容
        
        Args:
            file_path: 文件路径，如果为None则获取当前文件的内容
            
        Returns:
            str: 文件内容
        """
        # 确定文件路径
        if not file_path:
            file_path = self.current_file_path
        
        if not file_path or file_path not in self.file_content_cache:
            return ""
        
        return self.file_content_cache[file_path]
    
    def set_file_content(self, content, file_path=None):
        """设置文件内容
        
        Args:
            content: 文件内容
            file_path: 文件路径，如果为None则设置当前文件的内容
        """
        # 确定文件路径
        if not file_path:
            file_path = self.current_file_path
        
        if not file_path:
            return False, "没有指定文件路径"
        
        # 更新缓存
        self.file_content_cache[file_path] = content
        
        # 设置文件为已修改状态
        self.file_modified = True
        
        return True, "文件内容已更新"
    
    def is_file_modified(self):
        """检查当前文件是否已修改
        
        Returns:
            bool: 是否已修改
        """
        return self.file_modified
    
    def get_current_file_path(self):
        """获取当前文件路径
        
        Returns:
            str: 当前文件路径
        """
        return self.current_file_path
    
    def get_current_file_name(self):
        """获取当前文件名
        
        Returns:
            str: 当前文件名
        """
        if not self.current_file_path:
            return "未命名"
        return os.path.basename(self.current_file_path)
    
    def get_file_extension(self, file_path=None):
        """获取文件扩展名
        
        Args:
            file_path: 文件路径，如果为None则获取当前文件的扩展名
            
        Returns:
            str: 文件扩展名（包含点号）
        """
        # 确定文件路径
        if not file_path:
            file_path = self.current_file_path
        
        if not file_path:
            return ""
        
        _, ext = os.path.splitext(file_path)
        return ext.lower()
    
    def get_file_type(self, file_path=None):
        """获取文件类型
        
        Args:
            file_path: 文件路径，如果为None则获取当前文件的类型
            
        Returns:
            str: 文件类型
        """
        # 获取文件扩展名
        ext = self.get_file_extension(file_path)
        
        # 查找文件类型
        for file_type, extensions in self.supported_file_types.items():
            if ext in extensions:
                return file_type
        
        # 如果没有找到匹配的类型，返回"未知"
        return "未知"
    
    def get_file_size(self, file_path=None):
        """获取文件大小
        
        Args:
            file_path: 文件路径，如果为None则获取当前文件的大小
            
        Returns:
            int: 文件大小（字节）
        """
        # 确定文件路径
        if not file_path:
            file_path = self.current_file_path
        
        if not file_path or not os.path.exists(file_path):
            return 0
        
        return os.path.getsize(file_path)
    
    def get_file_modified_time(self, file_path=None):
        """获取文件修改时间
        
        Args:
            file_path: 文件路径，如果为None则获取当前文件的修改时间
            
        Returns:
            datetime: 文件修改时间
        """
        # 确定文件路径
        if not file_path:
            file_path = self.current_file_path
        
        if not file_path or not os.path.exists(file_path):
            return None
        
        return datetime.fromtimestamp(os.path.getmtime(file_path))
    
    def get_recent_files(self):
        """获取最近打开的文件列表
        
        Returns:
            list: 最近打开的文件列表
        """
        return self.recent_files
    
    def clear_recent_files(self):
        """清除最近打开的文件列表"""
        self.recent_files = []
    
    def search_files(self, directory, pattern="*"):
        """搜索文件
        
        Args:
            directory: 搜索目录
            pattern: 搜索模式
            
        Returns:
            list: 匹配的文件列表
        """
        import fnmatch
        
        matched_files = []
        
        try:
            # 检查目录是否存在
            if not os.path.exists(directory) or not os.path.isdir(directory):
                self.logger.error(f"目录 '{directory}' 不存在或不是目录")
                return matched_files
            
            # 遍历目录搜索文件
            for root, _, files in os.walk(directory):
                for file in files:
                    if fnmatch.fnmatch(file, pattern):
                        matched_files.append(os.path.join(root, file))
        except Exception as e:
            self.logger.error(f"搜索文件失败: {str(e)}")
        
        return matched_files
    
    def _add_to_recent_files(self, file_path):
        """添加文件到最近打开的文件列表
        
        Args:
            file_path: 文件路径
        """
        # 如果文件已经在列表中，先移除
        if file_path in self.recent_files:
            self.recent_files.remove(file_path)
        
        # 添加到列表开头
        self.recent_files.insert(0, file_path)
        
        # 保持列表大小不超过最大值
        if len(self.recent_files) > self.max_recent_files:
            self.recent_files = self.recent_files[:self.max_recent_files]
    
    def load_recent_files_from_config(self, config_file="config.json"):
        """从配置文件加载最近打开的文件列表
        
        Args:
            config_file: 配置文件路径
        """
        try:
            if os.path.exists(config_file):
                with open(config_file, "r", encoding="utf-8") as f:
                    config = json.load(f)
                    if "recent_files" in config:
                        self.recent_files = config["recent_files"]
                        # 过滤不存在的文件
                        self.recent_files = [f for f in self.recent_files if os.path.exists(f)]
        except Exception as e:
            self.logger.error(f"加载最近打开的文件列表失败: {str(e)}")
    
    def save_recent_files_to_config(self, config_file="config.json"):
        """保存最近打开的文件列表到配置文件
        
        Args:
            config_file: 配置文件路径
        """
        try:
            # 确保配置文件所在的目录存在
            config_dir = os.path.dirname(config_file)
            if config_dir and not os.path.exists(config_dir):
                os.makedirs(config_dir)
            
            # 读取现有配置
            config = {}
            if os.path.exists(config_file):
                with open(config_file, "r", encoding="utf-8") as f:
                    config = json.load(f)
            
            # 更新最近打开的文件列表
            config["recent_files"] = self.recent_files
            
            # 保存配置
            with open(config_file, "w", encoding="utf-8") as f:
                json.dump(config, f, indent=4, ensure_ascii=False)
        except Exception as e:
            self.logger.error(f"保存最近打开的文件列表失败: {str(e)}")
    
    def validate_file_path(self, file_path):
        """验证文件路径是否有效
        
        Args:
            file_path: 文件路径
            
        Returns:
            tuple: (是否有效, 消息)
        """
        try:
            # 检查文件路径是否为空
            if not file_path:
                return False, "文件路径不能为空"
            
            # 检查文件路径是否包含非法字符
            import re
            # Windows非法字符
            windows_invalid_chars = r'[<>:"/\\|?*]'
            # Linux/macOS非法字符（主要是NULL字符）
            unix_invalid_chars = r'\x00'
            
            if re.search(windows_invalid_chars, file_path) or re.search(unix_invalid_chars, file_path):
                return False, "文件路径包含非法字符"
            
            # 检查是否有写权限
            dir_path = os.path.dirname(file_path)
            if dir_path and not os.path.exists(dir_path):
                # 尝试创建目录来检查权限
                try:
                    os.makedirs(dir_path)
                    os.rmdir(dir_path)  # 删除创建的目录
                except PermissionError:
                    return False, "没有权限创建文件目录"
            elif dir_path and not os.access(dir_path, os.W_OK):
                return False, "没有权限写入文件目录"
            
            return True, "文件路径有效"
        except Exception as e:
            self.logger.error(f"验证文件路径失败: {str(e)}")
            return False, f"验证文件路径失败: {str(e)}"